package FanXingT;

import FanXingT.fclass.Apple;
import FanXingT.fclass.Food;
import FanXingT.fclass.Fruit;
import FanXingT.fclass.Plate;

import java.util.ArrayList;


/**
 * extends List<? extends Number> foo3的通配符声明，意味着以下的赋值是合法的：
 * 
 * // Number "extends" Number (in this context)
 * 
 * List<? extends Number> foo3 = new ArrayList<? extends Number>();
 * 
 * // Integer extends Number
 * 
 * List<? extends Number> foo3 = new ArrayList<? extends Integer>();
 * 
 * // Double extends Number
 * 
 * List<? extends Number> foo3 = new ArrayList<? extends Double>();
 * 
 * 1. 读取操作通过以上给定的赋值语句，你一定能从foo3列表中读取到的元素的类型是什么呢？你可以读取到Number，
 * 因为以上的列表要么包含Number元素， 要么包含Number的类元素。
 * 你不能保证读取到Integer，因为foo3可能指向的是List<Double>。你不能保证读取到Double，因为foo3可能指向的是List
 * <Integer>。
 * 
 * 2. 写入操作过以上给定的赋值语句，你能把一个什么类型的元素合法地插入到foo3中呢？你不能插入一个Integer元素，因为foo3可能指向List<
 * Double
 * >。你不能插入一个Double元素，因为foo3可能指向List<Integer>。你不能插入一个Number元素，因为foo3可能指向List
 * <Integer>。你不能往List<? extends
 * T>中插入任何类型的对象，因为你不能保证列表实际指向的类型是什么，你并不能保证列表中实际存储什么类型的对象
 * 。唯一可以保证的是，你可以从中读取到T或者T的子类。
 * 
 * super 现在考虑一下List<? super T>。 List<? super Integer> foo3的通配符声明，意味着以下赋值是合法的：
 * 1.// Integer is a "superclass" of Integer (in this context)
 * 
 * List<? super Integer> foo3 = new ArrayList<Integer>();
 * 
 * // Number is a superclass of Integer
 * 
 * List<? super Integer> foo3 = new ArrayList<Number>();
 * 
 * // Object is a superclass of Integer
 * 
 * List<? super Integer> foo3 = new ArrayList<Object>();
 * 1.读取操作通过以上给定的赋值语句，你一定能从foo3列表中读取到的元素的类型是什么呢？
 * 你不能保证读取到Integer，因为foo3可能指向List<Number>或者List<Object>。
 * 你不能保证读取到Number，因为foo3可能指向List<Object>。唯一可以保证的是
 * ，你可以读取到Object或者Object子类的对象（你并不知道具体的子类是什么）。
 * 2.写入操作通过以上给定的赋值语句，你能把一个什么类型的元素合法地插入到foo3中呢？
 * 你可以插入Integer对象，因为上述声明的列表都支持Integer。
 * 你可以插入Integer的子类的对象，因为Integer的子类同时也是Integer，原因同上。
 * 你不能插入Double对象，因为foo3可能指向ArrayList<Integer>。
 * 你不能插入Number对象，因为foo3可能指向ArrayList<Integer>。
 * 你不能插入Object对象，因为foo3可能指向ArrayList<Integer>。
 * 
 * Created by ${张英杰} on 2017/3/1. 在对泛型类型进行参数化时，类型参数的实例必须是引用类型，不能是基本类型。
 * 当一个变量被声明为泛型时，只能被实例变量、方法和内部类调用，而不能被静态变量 和静态方法调用。
 * 因为静态成员是被所有参数化的类所共享的，所以静态成员不应该有 类级别的类型参数。
 * 
 * 类中只有一个方法需要使用泛型，是使用类级别的泛型。 有道云：
 * http://note.youdao.com/noteshare?id=b0be94a3e6f52edc0ed3bb97cfb4c548
 */
public class FanXing_PESC {
	private final static String TAG = "FanXingActivity===";

	public static void main(String[] args) {
		// < ? extends FatherClass>
		ArrayList<? extends Fruit> lPlate = new ArrayList<Apple>();
		// ArrayList <? extends Fruit> l2Plate = new ArrayList<Food>();

		Plate<? extends Fruit> applePlate = new Plate(new Apple());
		Plate<Fruit> applePlate2 = new Plate(new Apple());
		System.out.println("Fruit new apple: "+applePlate2.getItem().toString());

		Plate applePlate3 = new Plate(new Apple());//可以
//		Plate<Fruit> p=new Plate<Apple>(new Apple());//不可以,但实际上Java编译器不允许这个操作。会报错，“装苹果的盘子”无法转换成“装水果的盘子”。
		Plate<? extends Fruit> p=new Plate<Apple>(new Apple());//可以

		Fruit item = applePlate.getItem();
		// 编译器在看到后面用Plate赋值以后，盘子里没有被标上有“苹果”。
		// 而是标上一个占位符：CAP#1，来表示捕获一个Fruit或Fruit的子类，
		// 具体是什么类不知道，代号CAP#1。
		// 然后无论是想往里插入Apple或者Meat
		// 或者Fruit编译器都不知道能不能和这个CAP#1匹配，所以就都不允许
		// applePlate.setItem(new Apple()); Error
		// applePlate.setItem(new Fruit()); Error
		Plate<? super Fruit> fPlate = new Plate(new Fruit());
		ArrayList<? super Fruit> f2Plate = new ArrayList<Food>();
//		ArrayList<? super Fruit> f3Plate = new ArrayList<Apple>();
		// 因为下界规定了元素的最小粒度的下限，实际上是放松了容器元素的类型控制。
		// 既然元素是Fruit的基类，那往里存粒度比Fruit小的都可以。
		// 但往外读取元素就费劲了，只有所有类的基类Object对象才能装下。但这样的话，元素的类型信息就全部丢失。
		fPlate.setItem(new Fruit());
//		 f2Plate.setItem(new Food());//Error
//		f2Plate.add(new Food());暂时没有搞懂为什么 不能放入food类
		fPlate.setItem(new Apple());
		Fruit ff = (Fruit) fPlate.getItem();
		System.out.println(fPlate.getItem());

	}

	// public void abc() {
	// Fan<Integer> fan = new Fan<Integer>();
	// fan.data = 1313;
	// }

}


